﻿using System;
using System.Collections.Generic;

namespace MyBasicLib.Extensions
{
    public class GenericEqualityComparer<T> : IEqualityComparer<T>
    {
        private readonly Func<T, T, Boolean> _comparer;
        private readonly Func<T, int> _hashCodeEvaluator;

        internal GenericEqualityComparer(Func<T, T, Boolean> comparer)
        {
            _comparer = comparer;
        }

        internal GenericEqualityComparer(Func<T, T, Boolean> comparer, Func<T, int> hashCodeEvaluator)
        {
            _comparer = comparer;
            _hashCodeEvaluator = hashCodeEvaluator;
        }

        #region IEqualityComparer<T> Members

        public bool Equals(T x, T y)
        {
            return _comparer(x, y);
        }

        public int GetHashCode(T obj)
        {
            if (obj == null)
            {
                throw new ArgumentNullException("obj");
            }
            if (_hashCodeEvaluator == null)
            {
                return 0;
            }
            return _hashCodeEvaluator(obj);
        }

        #endregion

        public static GenericEqualityComparer<T> Create<V>(Func<T, V> keySelector)
        {
            return Create(keySelector, EqualityComparer<V>.Default);
        }

        public static GenericEqualityComparer<T> Create<V>(Func<T, V> keySelector, IEqualityComparer<V> comparerV)
        {
            Func<T, T, Boolean> comparer = (x, y) => comparerV.Equals(keySelector(x), keySelector(y));
            Func<T, int> hashCodeEvaluator = x => comparerV.GetHashCode(keySelector(x));
            var equalityComparer = new GenericEqualityComparer<T>(comparer, hashCodeEvaluator);
            return equalityComparer;
        }

        public static GenericEqualityComparer<T> Create(Func<T, T, Boolean> comparer)
        {
            var equalityComparer = new GenericEqualityComparer<T>(comparer);
            return equalityComparer;
        }

        public static GenericEqualityComparer<T> Create(Func<T, T, Boolean> comparer, Func<T, int> hashCodeEvaluator)
        {
            var equalityComparer = new GenericEqualityComparer<T>(comparer, hashCodeEvaluator);
            return equalityComparer;
        }
    }
}